# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import Config

db = SQLAlchemy()


def create_app():
    app = Flask(__name__)
    app.config.from_object(Config)

    # 初始化数据库
    db.init_app(app)

    # 注册蓝图
    from .routes import auth_bp, user_bp, card_bp, trade_bp, admin_bp
    app.register_blueprint(auth_bp)
    app.register_blueprint(user_bp)
    app.register_blueprint(card_bp)
    app.register_blueprint(trade_bp)
    app.register_blueprint(admin_bp)

    return app


# config.py
import os


class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'bank-system-secret-key'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
                              'mysql+pymysql://root:123456@localhost/bank_system'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    UPLOAD_FOLDER = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'uploads')
    ALLOWED_EXTENSIONS = {'csv'}


# app/models/user.py
from app import db
from datetime import datetime


class UserInfo(db.Model):
    __tablename__ = 'user_info'

    customer_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    customer_name = db.Column(db.String(50), nullable=False)
    pid = db.Column(db.String(18), unique=True, nullable=False)
    telephone = db.Column(db.String(11), nullable=False)
    address = db.Column(db.String(255))
    create_time = db.Column(db.DateTime, default=datetime.utcnow)

    # 与银行卡的关联关系
    cards = db.relationship('CardInfo', backref='user', lazy=True)

    def to_dict(self):
        return {
            'customer_id': self.customer_id,
            'customer_name': self.customer_name,
            'pid': self.pid,
            'telephone': self.telephone,
            'address': self.address,
            'create_time': self.create_time.strftime('%Y-%m-%d %H:%M:%S')
        }


# app/routes/auth.py
from flask import Blueprint, render_template, redirect, url_for, request, flash, session
from app.models.user import UserInfo
from app import db
import re

auth_bp = Blueprint('auth', __name__, url_prefix='/auth')


@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 简单的登录验证，实际项目中应使用密码哈希
        pid = request.form.get('pid')
        password = request.form.get('password')  # 实际应为银行卡密码

        user = UserInfo.query.filter_by(pid=pid).first()
        if user:
            # 这里应该查询用户的银行卡并验证密码
            # 简化处理，假设密码正确
            session['user_id'] = user.customer_id
            flash('登录成功', 'success')
            return redirect(url_for('user.dashboard'))
        else:
            flash('身份证号或密码错误', 'error')

    return render_template('auth/login.html')


@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        name = request.form.get('name')
        pid = request.form.get('pid')
        telephone = request.form.get('telephone')
        address = request.form.get('address')

        # 验证输入
        if not name or not pid or not telephone:
            flash('请填写所有必填字段', 'error')
            return redirect(url_for('auth.register'))

        # 验证身份证号格式
        if not re.match(r'^\d{17}(\d|X|x)$', pid):
            flash('身份证号格式不正确', 'error')
            return redirect(url_for('auth.register'))

        # 验证手机号格式
        if not re.match(r'^1[3-9]\d{9}$', telephone):
            flash('手机号格式不正确', 'error')
            return redirect(url_for('auth.register'))

        # 检查身份证号是否已注册
        if UserInfo.query.filter_by(pid=pid).first():
            flash('该身份证号已注册', 'error')
            return redirect(url_for('auth.register'))

        # 创建新用户
        new_user = UserInfo(
            customer_name=name,
            pid=pid,
            telephone=telephone,
            address=address
        )

        try:
            db.session.add(new_user)
            db.session.commit()
            flash('注册成功，请登录', 'success')
            return redirect(url_for('auth.login'))
        except Exception as e:
            db.session.rollback()
            flash('注册失败，请稍后再试', 'error')
            print(e)

    return render_template('auth/register.html')


# app/services/card_service.py
from app.models.card import CardInfo
from app.models.trade import TradeRecord
from app import db
from datetime import datetime
import random


class CardService:
    def create_card(self, customer_id, saving_id=1):
        """创建银行卡，默认使用活期存款类型"""
        # 生成卡号
        card_id = f"10103576{random.randint(10000000, 99999999)}"

        # 获取存款类型信息
        from app.models.deposit import DepositType
        deposit_type = DepositType.query.get(saving_id)
        if not deposit_type:
            saving_id = 1  # 默认使用活期
            deposit_type = DepositType.query.get(saving_id)

        # 创建银行卡记录
        new_card = CardInfo(
            card_id=card_id,
            currency="RMB",
            open_date=datetime.now().date(),
            open_money=1.00,
            balance=1.00,
            password="888888",  # 默认密码
            is_report_loss=False,
            customer_id=customer_id,
            saving_id=saving_id
        )

        try:
            db.session.add(new_card)
            db.session.commit()
            return new_card
        except Exception as e:
            db.session.rollback()
            print(e)
            return None

    def deposit(self, card_id, amount):
        """存款操作"""
        if amount <= 0:
            return False, "存款金额必须大于0"

        card = CardInfo.query.filter_by(card_id=card_id).first()
        if not card:
            return False, "银行卡不存在"

        try:
            # 更新余额
            card.balance += amount
            card.last_trade_time = datetime.now()

            # 记录交易
            trade = TradeRecord(
                card_id=card_id,
                trade_type="存入",
                trade_money=amount,
                remark="存款"
            )
            db.session.add_all([card, trade])
            db.session.commit()
            return True, "存款成功"
        except Exception as e:
            db.session.rollback()
            print(e)
            return False, "存款失败，请稍后再试"

    def withdraw(self, card_id, amount):
        """取款操作"""
        if amount <= 0:
            return False, "取款金额必须大于0"

        card = CardInfo.query.filter_by(card_id=card_id).first()
        if not card:
            return False, "银行卡不存在"

        if card.balance < amount:
            return False, "余额不足"

        try:
            # 更新余额
            card.balance -= amount
            card.last_trade_time = datetime.now()

            # 记录交易
            trade = TradeRecord(
                card_id=card_id,
                trade_type="支取",
                trade_money=amount,
                remark="取款"
            )
            db.session.add_all([card, trade])
            db.session.commit()
            return True, "取款成功"
        except Exception as e:
            db.session.rollback()
            print(e)
            return False, "取款失败，请稍后再试"

    def transfer(self, from_card_id, to_card_id, amount, operator):
        """转账操作"""
        if amount <= 0:
            return False, "转账金额必须大于0"

        # 检查转出卡
        from_card = CardInfo.query.filter_by(card_id=from_card_id).first()
        if not from_card:
            return False, "转出银行卡不存在"

        # 检查转入卡
        to_card = CardInfo.query.filter_by(card_id=to_card_id).first()
        if not to_card:
            return False, "转入银行卡不存在"

        if from_card.balance < amount:
            return False, "转出卡余额不足"

        try:
            # 开启事务
            db.session.begin()

            # 转出
            from_card.balance -= amount
            from_card.last_trade_time = datetime.now()
            trade_from = TradeRecord(
                card_id=from_card_id,
                trade_type="转账",
                trade_money=amount,
                remark=f"转账至{to_card_id}",
                operator=operator
            )

            # 转入
            to_card.balance += amount
            to_card.last_trade_time = datetime.now()
            trade_to = TradeRecord(
                card_id=to_card_id,
                trade_type="转账",
                trade_money=amount,
                remark=f"接收来自{from_card_id}的转账",
                operator=operator
            )

            db.session.add_all([from_card, to_card, trade_from, trade_to])
            db.session.commit()
            return True, "转账成功"
        except Exception as e:
            db.session.rollback()
            print(e)
            return False, "转账失败，请稍后再试"